#include "Precompile.h"
#include "DX11VertexShader.h"
#include "DX11RenderSystem.h"
#include "DX11VertexInputLayout.h"

namespace Graphics{
	DX11VertexShader::DX11VertexShader(std::string &filename, RenderContext* handle):VertexShader(filename,handle),m_shader(NULL){
		DX11RenderContext* ctx = (DX11RenderContext*)handle;

		std::string shaderModel;

		switch(static_cast<DX11RenderSystem*>(ctx->m_renderSystem)->getFeatureLevel()){
		case D3D_FEATURE_LEVEL_9_1:
		case D3D_FEATURE_LEVEL_9_2:
			LOG_ERROR("Unsupported shader model");
			assert(0);
			return;
		case D3D_FEATURE_LEVEL_9_3:
			shaderModel = "vs_3_0";
			break;
		case D3D_FEATURE_LEVEL_10_0:
		case D3D_FEATURE_LEVEL_10_1:
			shaderModel = "vs_4_0";
			break;
		case D3D_FEATURE_LEVEL_11_0:
			shaderModel = "vs_5_0";
			break;
		}

		HRESULT hr;
		void* byteCode;
		size_t length;
		char buffer[10000];
		std::ifstream file(filename,std::ios::binary);
		file.read((char*)buffer,10000);
		byteCode = buffer;
		length = size_t(file.gcount());

		createInputLayout(filename,byteCode,length,handle);

		hr = ctx->m_handle->CreateVertexShader(byteCode,length,NULL,&m_shader);
		if(FAILED(hr)){
			LOG_ERROR("DX11VertexShader::DX11VertexShader - Failed in creating vertex shader.");
			assert(0);
		}

		file.close();
	}

	DX11VertexShader::~DX11VertexShader(){
		if(m_shader)
			m_shader->Release();
	}

	void DX11VertexShader::setShader(void* context){
		DX11RenderContext* ctx = (DX11RenderContext*)context;

		ctx->m_context->VSSetShader(m_shader,NULL,0);
	}

	void DX11VertexShader::createInputLayout(std::string &filename, void* byteData, size_t byteSize, RenderContext* handle){
		boost::shared_ptr<VertexInputLayout> vertLayout = boost::shared_ptr<DX11VertexInputLayout>(new DX11VertexInputLayout);

		std::string layoutFile = filename;
		layoutFile = layoutFile.substr(0,layoutFile.find_last_of('.'));
		layoutFile += ".layout";

		// Look for input data sig
		char buffer[256];
		std::string line,semantic,stride;
		std::ifstream file(layoutFile);
		{
			while(!file.eof()){
				file.getline(buffer,256);
				line = buffer;

				if(line.find("VS_INPUT") != std::string::npos){
					file.getline(buffer,256);
					line = buffer;
					while(true){
						file.getline(buffer,256);
						line = buffer;

						if(line.find("};") != std::string::npos)
							break;

						semantic = line.substr(line.find_first_of(':')+1,line.size());
						while(semantic.back() != ';'){
							semantic.pop_back();
						}
						semantic.pop_back();
						semantic = semantic.substr(semantic.find_first_not_of('	'),semantic.size());
						semantic = semantic.substr(semantic.find_first_not_of(' '),semantic.size());
						vertLayout->m_sematics.push_back(semantic);

						stride = line.substr(line.find_first_not_of('	'),line.find_first_of(':'));
						stride = stride.substr(stride.find_first_not_of(' '),stride.size());
						stride = stride.substr(0,stride.find_first_of(' '));
						stride = stride.back();

						if(Utility::StringConverter::isNumber(stride)){
							vertLayout->m_strides.push_back(Utility::StringConverter::parse<unsigned int>(stride));
						}
						else{
							vertLayout->m_strides.push_back(1);
						}
					}
					break;
				}
			}
		}
		file.close();

		std::string comparator;
		for(unsigned int i=0; i<vertLayout->m_sematics.size(); i++){
			comparator += vertLayout->m_sematics[i];
		}

		if(handle->m_materialManager->getInputLayoutId(comparator) == -1){
			vertLayout->buildLayout(handle,byteData,byteSize);
			m_inputLayoutId = handle->m_materialManager->addInputLayout(vertLayout);
		}
		else
			m_inputLayoutId = handle->m_materialManager->getInputLayoutId(comparator);
	}
}